package weiyao.CrawlerProcessor;

import us.codecraft.webmagic.Page;
import us.codecraft.webmagic.Site;
import us.codecraft.webmagic.processor.PageProcessor;
import weiyao.GUI.ScanResultCallback;
import weiyao.SiteManager;
import weiyao.Vul.VulnerabilityScanner;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashSet;

import java.util.Set;


//重写爬虫页面处理方法
public class CrawlerProcessor implements PageProcessor {
    private final SiteManager siteManager;
    private final VulnerabilityScanner vulnerabilityScanner;
    private final ScanResultCallback callback;
    private final String baseUrl;  // 存储用户输入的起始URL
    private final String baseHost;  // 存储基础主机名（域名或IP）
    private final int basePort;    // 存储基础端口
    private final boolean isIpAddress; // 标记是否是IP地址

    public CrawlerProcessor(SiteManager siteManager,
                            VulnerabilityScanner vulnerabilityScanner,
                            ScanResultCallback callback,
                            String baseUrl) {
        this.siteManager = siteManager;
        this.vulnerabilityScanner = vulnerabilityScanner;
        this.callback = callback;
        this.baseUrl = baseUrl;

        // 解析基础URL
        URI baseUri = extractBaseUri(baseUrl);
        this.baseHost = baseUri.getHost();
        this.basePort = baseUri.getPort();
        this.isIpAddress = isIpAddress(baseHost);
    }

    @Override
    public void process(Page page) {
        String currentUrl = page.getUrl().get();
        callback.onPageScanned(currentUrl);

        // 1. 执行漏洞扫描
        vulnerabilityScanner.scanPage(page, callback);

        // 2. 解析页面内容
        String htmlContent = page.getHtml().get();

        // 3. 提取所有有效的Less链接
        Set<String> lessLinks = ImageMapParser.extractLessLinks(htmlContent, currentUrl);

        // 4. 提取所有基础链接
        Set<String> baseLinks = ImageMapParser.extractBaseLinks(htmlContent, currentUrl);

        // 5. 合并所有链接
        Set<String> allLinks = new HashSet<>();
        allLinks.addAll(lessLinks);
        allLinks.addAll(baseLinks);

        // 6. 添加属于同一域名的链接
        for (String link : allLinks) {
            if (isSameDomain(link)) {
                page.addTargetRequest(link);
            }
        }
    }



    // 提取基础URI（增强错误处理）
    private URI extractBaseUri(String url) {
        try {
            URI uri = new URI(url);
            if (uri.getHost() == null) {
                callback.onError("无效的URL: " + url);
                throw new IllegalArgumentException("URL必须包含主机名");
            }
            return uri;
        } catch (URISyntaxException e) {
            callback.onError("无效的URL格式: " + url + " - " + e.getMessage());
            throw new IllegalArgumentException("无效的URL", e);
        }
    }

    // 检查链接是否属于同一域名
    private boolean isSameDomain(String url) {
        try {
            URI uri = new URI(url);
            String host = uri.getHost();
            int port = uri.getPort();

            if (host == null) {
                return false;
            }

            // 标准化主机名
            host = normalizeHost(host);

            // 检查主机名是否匹配
            if (!host.equals(baseHost)) {
                return false;
            }

            // 检查端口是否匹配（考虑默认端口）
            return portsMatch(port);
        } catch (URISyntaxException e) {
            return false;
        }
    }

    // 标准化主机名
    private String normalizeHost(String host) {
        // 移除www前缀
        if (host.startsWith("www.")) {
            host = host.substring(4);
        }

        // 如果是IP地址，标准化表示
        if (isIpAddress(host)) {
            return normalizeIpAddress(host);
        }

        return host;
    }

    // 检查是否是IP地址
    private boolean isIpAddress(String host) {
        return host.matches("\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}") ||
                "localhost".equalsIgnoreCase(host);
    }

    // 标准化IP地址表示
    private String normalizeIpAddress(String ip) {
        if ("localhost".equalsIgnoreCase(ip)) {
            return "127.0.0.1";
        }

        // 简化的IP标准化（实际应用中可能需要更复杂的处理）
        return ip;
    }

    // 检查端口是否匹配
    private boolean portsMatch(int port) {
        // 处理默认端口情况
        int effectiveBasePort = (basePort == -1) ? getDefaultPortForScheme() : basePort;
        int effectivePort = (port == -1) ? getDefaultPortForScheme() : port;

        return effectiveBasePort == effectivePort;
    }

    // 根据基础URL方案获取默认端口
    private int getDefaultPortForScheme() {
        try {
            URI baseUri = new URI(baseUrl);
            String scheme = baseUri.getScheme();
            if ("http".equalsIgnoreCase(scheme)) {
                return 80;
            } else if ("https".equalsIgnoreCase(scheme)) {
                return 443;
            }
        } catch (URISyntaxException e) {
            // 忽略
        }
        return 80; // 默认HTTP端口
    }


    @Override
    public Site getSite() {
        return siteManager.getCurrentSite();
    }
}